package com.gw.booking.service;

import com.gw.booking.common.ApiException;
import com.gw.booking.common.Constant;
import com.gw.booking.common.MessageCode;
import com.gw.booking.common.Util;
import com.gw.booking.dto.PageDto;
import com.gw.booking.dto.backend.DiscountDetailDto;
import com.gw.booking.dto.backend.DiscountDto;
import com.gw.booking.dto.backend.DiscountListDtoOut;
import com.gw.booking.entity.CustomerDiscount;
import com.gw.booking.entity.Discount;
import com.gw.booking.entity.LoginToken;
import com.gw.booking.entity.Logs;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class DiscountService {
    @Autowired
    private SessionFactory sessionFactory;
    @Autowired
    private LogService logService;

    public PageDto<DiscountListDtoOut> list(String shopName, String manager, Integer isLimited, Integer merchantTypeId, int page, int size, LoginToken loginToken)
            throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Session session = sessionFactory.getCurrentSession();
        Map<String, Object> params = new HashMap<>();
        params.put("cityId", loginToken.getCityId());
        String hqlCount = " select count(*) from discount d inner join merchant m on  d.merchant_id = m.id " +
                " inner join merchant_type mt on mt.id = m.merchant_type_id ";
        String hql = " select d.id as id, m.id as merchantId, " +
                " m.shop_name as shopName, m.manager, d.state as state, d.limited as limited, " +
                " d.limited_at as limitedAt, d.reserve as reserve, d.prompt as prompt, " +
                " d.condition_c as conditionC, d.condition_j as conditionJ, d.content_c as contentC,d.content_j as contentJ,  " +
                " m.merchant_type_id as merchantTypeId, mt.type_name as merchantTypeName " +
                " from discount d " +
                " inner join merchant m on  d.merchant_id = m.id " +
                " inner join merchant_type mt on mt.id = m.merchant_type_id ";
        String hqlWhere = " where 1 = 1 and m.city_id = :cityId ";
        if (StringUtils.isNotBlank(shopName)) {
            params.put("shopName", "%" + shopName + "%");
            hqlWhere += " and m.shop_name like :shopName ";
        }
        if (StringUtils.isNotBlank(manager)) {
            params.put("manager", "%" + manager + "%");
            hqlWhere += " and m.manager like :manager ";
        }
        if (isLimited != null) {
            params.put("nowTime", new Date());
            if (isLimited.equals(Constant.FALSE)) {
                hqlWhere += " and d.limited_at<:nowTime";
            } else {
                hqlWhere += " and d.limited_at>=:nowTime";
            }
        }
        if (merchantTypeId != null) {
            params.put("merchantTypeId", merchantTypeId);
            hqlWhere += " and m.merchant_type_id = :merchantTypeId ";
        }
        BigInteger total = (BigInteger) session.createSQLQuery(hqlCount + hqlWhere)
                .setProperties(params)
                .uniqueResult();
        List<DiscountListDtoOut> items = session.createSQLQuery(hql + hqlWhere)
                .setProperties(params)
                .setResultTransformer(Transformers.aliasToBean(DiscountListDtoOut.class))
                .setFirstResult(Util.calFirst(page, size))
                .setMaxResults(size)
                .list();
        return new PageDto(page, size, total.longValue(), items);
    }

    public DiscountListDtoOut detail(Integer discountId, LoginToken loginToken) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Session session = sessionFactory.getCurrentSession();
        String hql = " select d.id as id, m.id as merchantId, " +
                " m.shop_name as shopName, m.manager, d.state as state, d.limited as limited, " +
                " d.limited_at as limitedAt, d.reserve as reserve, d.prompt as prompt, " +
                " d.condition_c as conditionC, d.condition_j as conditionJ, d.content_c as contentC,d.content_j as contentJ " +
                " from discount d " +
                " inner join merchant m on  d.merchant_id = m.id ";
        String hqlWhere = " where 1 = 1 and d.id = :discountId and m.city_id = :cityId";
        DiscountListDtoOut discountListDtoOut = (DiscountListDtoOut) session.createSQLQuery(hql + hqlWhere)
                .setParameter("discountId", discountId)
                .setParameter("cityId", loginToken.getCityId())
                .setResultTransformer(Transformers.aliasToBean(DiscountListDtoOut.class))
                .uniqueResult();
        return discountListDtoOut;
    }

    public void txAdd(LoginToken loginToken, DiscountDto discountDto) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Session session = sessionFactory.getCurrentSession();
        Timestamp ts = new Timestamp(System.currentTimeMillis());
        Discount discount = new Discount();
        PropertyUtils.copyProperties(discount, discountDto);
        discount.setCreatedAt(ts);
        session.save(discount);
        session.flush();
        logService.txAddLog(Logs.LogType.add, loginToken.getUserId(), "新增优惠：" + discount.getId());
    }

    public void txUpdate(LoginToken loginToken, DiscountDetailDto discountDetailDto) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Session session = sessionFactory.getCurrentSession();
        Timestamp ts = new Timestamp(System.currentTimeMillis());
        Discount discount = (Discount) session.get(Discount.class, discountDetailDto.getDiscountId());
        PropertyUtils.copyProperties(discount, discountDetailDto);
        discount.setUpdatedAt(ts);
        session.save(discount);
        session.flush();
        logService.txAddLog(Logs.LogType.edit, loginToken.getUserId(), "编辑优惠：" + discount.getId());
    }

    public List<DiscountListDtoOut> merchantDiscountList(LoginToken loginToken, Integer merchantId)
            throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Session session = sessionFactory.getCurrentSession();
        Map<String, Object> params = new HashMap<>();
        params.put("merchantId", merchantId);
        params.put("customerId", loginToken.getUserId());
        String hqlCount = " select count(*) from discount d inner join merchant m on  d.merchant_id = m.id ";
        String hql = " select d.id as id, m.id as merchantId, cd.id as customerDiscountId, " +
                " m.shop_name as shopName, m.manager, d.state as state, d.limited_at as limitedAt, " +
                " d.limited as limited, d.reserve as reserve, d.prompt as prompt, " +
                " d.condition_c as conditionC, d.condition_j as conditionJ, d.content_c as contentC,d.content_j as contentJ " +
                " from discount d " +
                " inner join merchant m on  d.merchant_id = m.id " +
                " left join customer_discount cd on cd.discount_id = d.id and cd.customer_id = :customerId ";
        String hqlWhere = " where 1 = 1 and d.state = 1 and d.merchant_id = :merchantId";
        BigInteger total = (BigInteger) session.createSQLQuery(hqlCount + hqlWhere)
                .setProperties(params)
                .uniqueResult();
        List<DiscountListDtoOut> items = session.createSQLQuery(hql + hqlWhere)
                .setProperties(params)
                .setResultTransformer(Transformers.aliasToBean(DiscountListDtoOut.class))
                .list();
        return items;
    }

    public void txAutoUpdate() throws ParseException {
        Session session = sessionFactory.getCurrentSession();
        String sql = "update discount set state = 0 and  updated_at = :time where limited_at < :time ";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        session.createSQLQuery(sql).setParameter("time", sdf.parse(sdf.format(new Date()))).executeUpdate();
    }

    public void txDelete(LoginToken loginToken, Integer discountId) {
        Session session = sessionFactory.getCurrentSession();
        Discount discount = (Discount) session.get(Discount.class, discountId);
        if (discount == null) {
            throw new ApiException(MessageCode.CODE_PARAMETER_ERROR);
        }
        session.delete(discount);
        logService.txAddLog(Logs.LogType.delete, loginToken.getUserId(), "删除优惠：" + discountId);
    }
}
